/**
 * Copyright (c) by Shanghai PoleLink Information Technology Co.,Ltd. All rights reserved.
 * <p>
 * This software is copyright protected and proprietary to Shanghai PoleLink
 * Information Technology. Shanghai PoleLink Information Technology Co.,Ltd
 * grants to you only those rights as set out in the license conditions.
 * All other rights remain with Shanghai PoleLink Information Technology Co.,Ltd.
 **/
package com.polelink.testcenter.runner;

import com.polelink.testcenter.converter.DTCToIniConverter;
import com.polelink.testcenter.dto.EcuConfigDto;
import com.polelink.testcenter.dto.EcuInfoDto;
import com.polelink.testcenter.dto.ProjectItemDto;
import com.polelink.testcenter.dto.VehicleInfoDto;
import com.polelink.testcenter.exception.DtcException;
import com.polelink.testcenter.exception.ExcelParseException;
import com.polelink.testcenter.service.ExcelParserService;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.util.Pair;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import static com.polelink.testcenter.constant.Constant.ERROR_LOG_FORMAT;

/**
 * ClassName: CustomerRunner Description:
 *
 * @author lihao
 * @since 2024-10-18 10:52:35
 */
@Component
@Slf4j
public class CustomerRunner implements ApplicationRunner {
    @Resource
    private ExcelParserService excelParserService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        FileProcessContext context = validateArguments(args);
//        initLogSystem(context);

        processExcelFile(context);
        processDtcFile(context);
    }

    private FileProcessContext validateArguments(ApplicationArguments args) {
        if (args.getSourceArgs().length != 3) {
            throw new RuntimeException("文件参数错误，需要3个参数：[DTC路径] [Excel路径] [基础目录]");
        }
        return new FileProcessContext(
                sanitizePath(args.getSourceArgs()[0]),
                sanitizePath(args.getSourceArgs()[1]),
                sanitizePath(args.getSourceArgs()[2])
        );
    }

    private String sanitizePath(String rawPath) {
        return rawPath.replace("\"", "");
    }

    private void initLogSystem(FileProcessContext context) {
        String logFilePath = buildLogFilePath(context.baseDir());
        System.setProperty("log.path", logFilePath);
        createLogDirectory(logFilePath);
        log.info("日志系统初始化完成，路径：{}", logFilePath);
    }

    private String buildLogFilePath(String baseDir) {
        return baseDir + File.separator + "log" + File.separator
                + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + ".log";
    }

    private void createLogDirectory(String logFilePath) throws RuntimeException {
        File logDir = new File(logFilePath).getParentFile();
        if (!logDir.exists() && !logDir.mkdirs()) {
            throw new RuntimeException("无法创建日志目录：" + logDir.getAbsolutePath());
        }
    }

    private void processExcelFile(FileProcessContext context) {
        executeWithExceptionHandling("Excel", () -> {
            Workbook workbook;
            try {
                workbook = loadWorkbook(context.excelPath());
                processExcelData(workbook, context.baseDir());
            } catch (Exception e) {
                throw new ExcelParseException("Excel文件解析失败", e);
            }
        }, context.excelPath());
    }

    private Workbook loadWorkbook(String excelPath) throws Exception {
        return WorkbookFactory.create(Files.newInputStream(Paths.get(excelPath)));
    }

    private void processExcelData(Workbook workbook, String baseDir) throws Exception {
        List<EcuInfoDto> ecuInfos = excelParserService.parseEcuInfo(workbook.getSheet("ECU Info"));
        Pair<VehicleInfoDto, List<EcuConfigDto>> ecuConfigs =
                excelParserService.parseEcuConfig(ecuInfos, workbook.getSheet("ECU Config"));
        List<ProjectItemDto> pepsItems = excelParserService.parsePepsSheet(workbook.getSheet("PEPS"));

        generateIniFile(ecuInfos, ecuConfigs, pepsItems, baseDir);
    }

    private void generateIniFile(List<EcuInfoDto> ecuInfos,
                                 Pair<VehicleInfoDto, List<EcuConfigDto>> ecuConfigs,
                                 List<ProjectItemDto> pepsItems,
                                 String baseDir) throws Exception {
        String iniContent = excelParserService.generateIniContent(ecuInfos, ecuConfigs, pepsItems);
        Path outputPath = buildOutputPath(baseDir);
        writeFileContent(outputPath, iniContent);
    }

    private Path buildOutputPath(String baseDir) {
        return Paths.get(baseDir, "excel", "ECUInfo.ini");
    }

    private void writeFileContent(Path outputPath, String content) throws Exception {
        Files.createDirectories(outputPath.getParent());
        Files.writeString(outputPath, content, StandardCharsets.UTF_8);
        log.info("INI文件生成成功：{}", outputPath.toAbsolutePath());
    }

    private void processDtcFile(FileProcessContext context) {
        executeWithExceptionHandling("DTC", () -> {
            try {
                processFile(context.dtcPath(), context.baseDir(), (filePath, base) -> {
                    DTCToIniConverter.parse(filePath, base);
                    return buildDtcOutputPath(filePath, base);
                });
            } catch (Exception e) {
                throw new DtcException("DTC文件处理失败", e);
            }
        }, context.dtcPath());
    }

    private void processFile(String filePath, String baseDir, FileProcessor processor) throws Exception {
        String outputPath = processor.process(filePath, baseDir);
        ensureParentDirectoryExists(outputPath);
        log.info("DTC文件处理完成，输出路径：{}", outputPath);
    }

    private String buildDtcOutputPath(String filePath, String baseDir) {
        return Paths.get(baseDir, "dtc", new File(filePath).getName().replace(".csv", ".ini")).toString();
    }

    private void ensureParentDirectoryExists(String filePath) {
        new File(filePath).getParentFile().mkdirs();
    }

    private void executeWithExceptionHandling(String module, Runnable task, String filePath) {
        try {
            log.info("[{}] 开始处理文件：{}", module, filePath);
            task.run();
            log.info("[{}] 文件处理完成：{}", module, filePath);
        } catch (ExcelParseException e) {
            handleBusinessException(module, e, filePath);
        } catch (Exception e) {
            handleSystemException(module, e, filePath);
        }
    }

    private void handleBusinessException(String module, ExcelParseException e, String filePath) {
        log.error("[{}] 业务处理异常 - 文件：{}\n错误信息：{}", module, filePath, e.getMessage(), e);
    }

    private void handleSystemException(String module, Exception e, String filePath) {
        String errorDetails = buildErrorDetails(e);
        log.error("[{}] 系统异常 - 文件：{}\n{}", module, filePath, errorDetails);
    }

    private String buildErrorDetails(Exception e) {
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw));
        return String.format(ERROR_LOG_FORMAT,
                e.getClass().getSimpleName(),
                e.getMessage(),
                sw);
    }

    @FunctionalInterface
    private interface FileProcessor {
        String process(String filePath, String baseDir) throws Exception;
    }

        private record FileProcessContext(String dtcPath, String excelPath, String baseDir) {
    }
}